package org.example.fboot.config;

import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import lombok.extern.slf4j.Slf4j;
import org.example.fboot.annotation.MessageHandler;
import org.example.fboot.annotation.RequestHandler;
import org.example.fboot.handler.BusException;
import org.example.fboot.proto.RequestMessageOuterClass;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 将声明了 {@link MessageHandler} 注解的注册成为控制器
 */
@Slf4j
@Component
public class WsPostProcessor implements BeanPostProcessor {

    private Map<String, Method> methodMap;
    private final Map<String,Object> beanMap=new ConcurrentHashMap<>();
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> beanClass = bean.getClass();
        MessageHandler annotation = beanClass.getAnnotation(MessageHandler.class);
        if (Objects.nonNull(annotation)) {
            methodMap = Arrays.stream(beanClass.getDeclaredMethods())
                    .filter(m -> m.getAnnotation(RequestHandler.class) != null)
                    .collect(Collectors.toMap(m -> m.getAnnotation(RequestHandler.class).value(), m -> m));
            methodMap.forEach((k,v)-> beanMap.put(k,bean));
        }
        return bean;
    }

    public <R extends Message,T extends Message> void precess(RequestMessageOuterClass.RequestMessage requestMessage, Consumer<R> consumer) throws InvocationTargetException, IllegalAccessException, InvalidProtocolBufferException {
        Method method = methodMap.get(requestMessage.getPath());
        if (method==null){
            throw new BusException("path: ["+requestMessage.getPath()+"] 不存在");
        }
        Object o = beanMap.get(requestMessage.getPath());
        if (method.getParameterTypes().length>0){
            Class<?> parameterType = method.getParameterTypes()[0];
            R invoke = (R) method.invoke(o, requestMessage.getData().unpack((Class<T>) parameterType));
            consumer.accept(invoke);
        }else {
            consumer.accept((R) method.invoke(o));
        }

    }
}
